/*
 * Copyright (c) Jack魏 2023 - 2023, All Rights Reserved.
 */

package cn.jackwei.yiyi.util;

import cn.dev33.satoken.stp.StpUtil;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.io.resource.ClassPathResource;
import cn.hutool.core.text.CharSequenceUtil;
import cn.hutool.core.util.ArrayUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.Part;
import lombok.extern.slf4j.Slf4j;
import org.lionsoul.ip2region.xdb.Searcher;

import java.io.File;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;

/**
 * Web工具类
 *
 * @author Jack魏
 * @since 2023/10/20
 */
@Slf4j
public class WebUtil {
    /**
     * unknown常量
     */
    private static final String UNKNOWN = "unknown";

    /**
     * ip查询
     */
    private static Searcher SEARCHER = null;

    /**
     * 不能实例化
     */
    private WebUtil() {
    }

    /**
     * 获取ip地址
     *
     * @param request 请求对象
     * @return ip
     */
    public static String getIpAddress(HttpServletRequest request) {
        String ip = request.getHeader("x-forwarded-for");
        ip = getHeaderValue(ip, "Proxy-Client-IP", request);
        ip = getHeaderValue(ip, "WL-Proxy-Client-IP", request);
        ip = getHeaderValue(ip, "HTTP_X_FORWARDED_FOR", request);
        ip = getHeaderValue(ip, "HTTP_X_FORWARDED", request);
        ip = getHeaderValue(ip, "HTTP_X_CLUSTER_CLIENT_IP", request);
        ip = getHeaderValue(ip, "HTTP_CLIENT_IP", request);
        ip = getHeaderValue(ip, "HTTP_FORWARDED_FOR", request);
        ip = getHeaderValue(ip, "HTTP_FORWARDED", request);
        ip = getHeaderValue(ip, "HTTP_VIA", request);
        ip = getHeaderValue(ip, "REMOTE_ADDR", request);
        if (CharSequenceUtil.isBlank(ip) || UNKNOWN.equalsIgnoreCase(ip)) {
            ip = request.getRemoteAddr();
        }
        // 本地地址
        if ("127.0.0.1".equals(ip) || "0:0:0:0:0:0:0:1".equals(ip)) {
            // 客户端和服务端是在同一台机器上、获取本机的IP
            try {
                InetAddress inetAddress = InetAddress.getLocalHost();
                ip = inetAddress.getHostAddress();
            } catch (UnknownHostException e) {
                log.error("ip error", e);
            }
        }
        return ip;
    }

    /**
     * 获取header值
     *
     * @param ip      ip地址
     * @param header  获取请求头key
     * @param request 请求
     * @return ip地址
     */
    private static String getHeaderValue(String ip, String header, HttpServletRequest request) {
        String newIp = ip;
        if (CharSequenceUtil.isBlank(ip) || UNKNOWN.equalsIgnoreCase(ip)) {
            newIp = request.getHeader(header);
        }
        return newIp;
    }

    /**
     * 根据请求获取参数
     *
     * @param request 请求
     * @return 请求参数map
     */
    public static Map<String, String> getParameterMap(HttpServletRequest request) {
        Map<String, String> requestParameterMap = new HashMap<>();
        Map<String, String[]> parameterMap = request.getParameterMap();
        if (parameterMap != null && parameterMap.size() > 0) {
            String key = null;
            String[] values = null;
            for (Map.Entry<String, String[]> entry : parameterMap.entrySet()) {
                key = entry.getKey();
                values = parameterMap.get(key);
                String value = ArrayUtil.isNotEmpty(values) ? ArrayUtil.join(values, ",") : "";
                requestParameterMap.put(key, value);
            }
        }

        try {
            final Collection<Part> parts = request.getParts();
            for (Part part : parts) {
                requestParameterMap.put(part.getName(), part.getSubmittedFileName());
            }
        } catch (Exception exception) {
            // 正常的请求会报异常，这里不需要处理即可。
        }
        return requestParameterMap;
    }

    /**
     * 获取当前登录用户id
     *
     * @return 用户id
     */
    public static String getUserId() {
        try {
            return StpUtil.getLoginIdAsString();
        } catch (Exception exception) {
            return StrUtil.EMPTY;
        }
    }

    static {
        String fileName = System.getProperty("yiyi.file.local.path") + File.separator + "ip2region.xdb";
        File dbFile = FileUtil.file(fileName);
        if (!FileUtil.exist(dbFile)) {
            ClassPathResource fileStream = new ClassPathResource(fileName);
            if (ObjectUtil.isEmpty(fileStream.getStream())) {
                log.error("IP地址库不存在：{}", fileName);
            }
            FileUtil.writeFromStream(fileStream.getStream(), dbFile);
        }

        String dbPath = dbFile.getPath();
        // 加载整到内存。
        byte[] memory = new byte[0];
        try {
            memory = Searcher.loadContentFromFile(dbPath);
        } catch (Exception e) {
            log.error("从ip2region.xdb文件加载内容失败: {}", e.getMessage());
        }
        // 创建完全基于内存的查询对象。
        try {
            SEARCHER = Searcher.newWithBuffer(memory);
        } catch (Exception e) {
            log.error("初始化失败：{}", e.getMessage());
        }
    }

    /**
     * 根据IP地址获取离线城市信息
     *
     * @param ip IP地址
     */
    public static String getCityInfo(String ip) {
        try {
            String region = SEARCHER.search(ip.trim());
            return region.replace("0|", "").replace("|0", "");
        } catch (Exception e) {
            log.error("IP地址获取城市异常,IP:{}, {}", ip, e.getMessage());
            return "未知";
        }
    }
}
